//
//                         LogRec.h
//
#ifndef LOGREC_H
#define LOGREC_H
#include <iostream>
#include <sstream>
#include <fstream>
#include <deque>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <services/StateService/State.h>
#include <utils/UtilTimer.h>

struct TimeStampedState
{
TimeStampedState(unsigned int size)
: states(size)
  {
  }
  struct timeval time;
  std::vector<StatePtr> states;
};

class LogRec {
 public:
  LogRec()
    {
      initialize_log();
      set_file_date();
      m_file_prefix = "/tmp/";
      m_file_suffix = "log";
      m_instname = "";
      firstflag = true;
      m_oneloglength = 120.0;//default log length is 120[s]
    }

  ~LogRec() {}

  void set_file_prefix(std::string prfx){ m_file_prefix = prfx;}
  void set_file_sufix( std::string sufx){ m_file_suffix = sufx;}
  void set_file_date(void){ m_file_date = m_timer.get_starttime();}
  void set_instance_name(std::string name){ m_instname = name; }
  void set_onelog_length(double length){ m_oneloglength = length; }
  void initialize_log(void){ m_buffer.clear(); }
  void set_data( std::vector<StatePtr> states){

    if(firstflag){
      stypes.resize(states.size(), RTMEUS::FLOATSEQ_TYPE);
      snames.resize(states.size(), "test");
      firstflag = false;
    }

    TimeStampedState copied_states(states.size());
    copied_states.time = m_timer.current();
    m_buffer.push_front(copied_states);

    for(unsigned int i=0;i < states.size(); i ++)
      {
	m_buffer.front().states[i] = states[i]->copy();
	stypes[i] = states[i]->getStateProfile().type;
	snames[i] = states[i]->name();
      }
  }

  void logger(int* rflag){
    while(*rflag){
      set_file_date();
      logger_core(rflag);
    }
  }

  void logger_core(int *rflag){
    logf_name = m_file_prefix + m_instname + "_" + m_file_date + "_lisp." + m_file_suffix;
    std::string cpplog_name;
    cpplog_name = m_file_prefix + m_instname + "_" + m_file_date + "_cpp." + m_file_suffix;

    std::cerr << "Start logging to " << logf_name << std::endl;
    std::cerr << "Start logging to " << cpplog_name << std::endl;

    std::fstream fstrm( logf_name.c_str(), std::ios::out );
    std::fstream cppstrm( cpplog_name.c_str(), std::ios::out );

    fstrm << ";;" << std::endl;
    fstrm << ";; This file is generated by RTMEUS LogRec Class" << std::endl;
    fstrm << ";; started at " << m_file_date;
    fstrm << ";;" << std::endl;

    while(*rflag)
      {
	
	if(m_timer.time() > m_oneloglength) break;

	while(*rflag) {
	  {
	    if (m_buffer.size() > 1) break;
	  }
	  usleep(1000);
	}		

	if (*rflag)
	  {
	    std::stringstream ss;
	    TimeStampedState &timedstate = m_buffer.back();
	    //
	    ss << "#s(rtmeus-log rtmstates #s(RTMStates ";
	    for(unsigned int i = 0; i < timedstate.states.size(); i++)
	      {
		StatePtr &state = timedstate.states[i];
		StateElementFuncPtr func = StateElementFuncBase::create(stypes[i]);
		ss << snames[i] << " #" << func->getSprefix() << "(";
		for(unsigned int j=0;j<state->getLength();j++)
		  {
		    if (j != 0) ss << " ";
		    func->store(ss, state->getPtr(j));
		  }
		ss << ") ";
	      }
	    ss << ") abstime #f(" << timedstate.time.tv_sec << " " << timedstate.time.tv_usec / 1000 /*[msec]*/ << ")";
	    ss << ") " << std::endl;
	    fstrm << ss.str();

	    // cpp log
	    std::stringstream cppss;
	    cppss << "abstime " << timedstate.time.tv_sec << " " << timedstate.time.tv_usec / 1000 /*[msec]*/;
	    for(unsigned int i=0; i<timedstate.states.size(); i++){
	      //cppss << "," << snames[i] << " " << stypes[i];
	      cppss << "," << snames[i] << " " << "FLOATSEQ";
	      StatePtr &state = timedstate.states[i];
	      cppss << " " << state->getLength();
	      StateElementFuncPtr func = StateElementFuncBase::create(stypes[i]);
	      for(unsigned int j=0;j<state->getLength();j++){
		cppss << " ";
		func->store(cppss, state->getPtr(j));
	      }
	    }
	    cppss << std::endl;
	    cppstrm << cppss.str();

	    //
	    m_buffer.pop_back();
	  }
      }
    fstrm.close();
    std::cerr << "recored to" <<  logf_name << std::endl;
    std::cerr << "recored to" <<  cpplog_name << std::endl;
  }

  void start_log(void){
    recflag = 1;
    log_thr.create_thread(boost::bind(&LogRec::logger, this, &recflag));
  }

  void stop_log(void){
    recflag = 0;
    log_thr.join_all();
  }

  void make_lispclass( std::vector<StatePtr> states, std::string compn){
    std::vector<RTMEUS::StateType> tmp_stypes;
    std::vector<std::string> tmp_snames;

    // 設定ファイルの読み込み
    tmp_stypes.resize(states.size(), RTMEUS::FLOATSEQ_TYPE);
    tmp_snames.resize(states.size(), "test");

    for(unsigned int i = 0; i < states.size(); i++){
      try {
	//StatePtr state = StateBase::create(*states[i]);
	tmp_stypes[i]=states[i]->getStateProfile().type;
	tmp_snames[i]=states[i]->name();
      } catch(std::runtime_error &e) {
	std::cerr << e.what() << ":: ignored" << std::endl;
      }
    }
    
    std::string lispfn = std::string(getenv("RTMEUSDIR")) + std::string("/RTMEus/")
      + std::string(getenv("ARCHDIR")) + std::string("/bin/") 
      + std::string("rtmstate_") + compn + std::string(".l") ;

    std::cerr << logf_name << std::endl;
    std::fstream fstrm( lispfn.c_str(), std::ios::out );

    fstrm << ";;" << std::endl;
    fstrm << ";; This file is generated by RTMEUS LogRec Class" << std::endl;
    fstrm << ";; RTMStates interpretation class" << std::endl;
    fstrm << ";;" << std::endl;
        
    fstrm << "(defclass RTMStates " << std::endl;
    fstrm << "  :super propertied-object" << std::endl;
    fstrm << "  :slots ("<< std::endl;

    for(unsigned int i = 0;i < tmp_stypes.size(); i++){
      fstrm << "         (" << tmp_snames[i] << " :type ";
      if (tmp_stypes[i] == RTMEUS::CHARSEQ_TYPE || tmp_stypes[i] == RTMEUS::SHORTSEQ_TYPE || tmp_stypes[i] == RTMEUS::LONGSEQ_TYPE)
	fstrm << "integer-vector)"<< std::endl;
      else if (tmp_stypes[i] == RTMEUS::FLOATSEQ_TYPE || tmp_stypes[i] == RTMEUS::DOUBLESEQ_TYPE)
	fstrm << "float-vector)"<< std::endl;
      else
	fstrm << "vector)" << std::endl;
    }

    fstrm << "         )" << std::endl;
    fstrm << "  )" << std::endl;
        
    fstrm << "(defmethod RTMStates" << std::endl;
    fstrm << "  (:init &key ";

    for(unsigned int i = 0;i < tmp_stypes.size(); i++)
      fstrm << "((:" << tmp_snames[i] << " tmp" << i << "))";

    fstrm << std::endl;
        
    for(unsigned int i = 0;i < tmp_stypes.size(); i++)
      fstrm << "   (setq " << tmp_snames[i] << " tmp" << i << ")" << std::endl;
             
    fstrm << "   self)" << std::endl;

    for(unsigned int i = 0;i < tmp_stypes.size(); i++){
      fstrm << "  (:" << tmp_snames[i] << std::endl;
      fstrm << "   (&optional (new-vector))" << std::endl;
      fstrm << "   (if new-vector (setq " << tmp_snames[i] << " new-vector))" << std::endl;
      fstrm << "   " << tmp_snames[i] << ")" << std::endl;
    }

    fstrm << "  )" << std::endl;       

    fstrm.close();

    std::cerr << "made " <<  lispfn << std::endl;        
  }

    
 private:
  std::deque<TimeStampedState> m_buffer;
  std::string m_file_date;
  std::string m_file_prefix;
  std::string m_instname;
  std::string m_file_suffix;
  std::string logf_name;
  std::vector<RTMEUS::StateType> stypes;
  std::vector<std::string> snames;
  bool firstflag;
  int recflag;
  boost::thread_group log_thr;
  UtilTimer m_timer;
  double m_oneloglength;
};

#endif //LOGREC_H


